import { Component, inject, OnInit } from '@angular/core';
import { TreeModule } from 'primeng/tree';
import { TreeNode, TreeDragDropService, MessageService, ConfirmationService } from 'primeng/api';
import { ToastModule } from 'primeng/toast';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { DrawerModule } from 'primeng/drawer';
import { InputTextModule } from 'primeng/inputtext';
import { InputNumberModule } from 'primeng/inputnumber';
import { FormsModule } from '@angular/forms';
import { ColorPickerModule } from 'primeng/colorpicker';
import { CheckboxModule } from 'primeng/checkbox';
import { DialogModule } from 'primeng/dialog';
import { ProgressBarModule } from 'primeng/progressbar';
import { ButtonModule } from 'primeng/button';
import { ContextMenuModule } from 'primeng/contextmenu';
import { MenuItem } from 'primeng/api';
import { v4 as uuid } from 'uuid';
import { ElectronService } from '@/service/electron.service';
import { DataSaveService } from '../service/data-save.service';
import { KmlWriterService } from '../service/kml-writer.service';
import { TrackLineService } from '../service/track-line.service';
import { EditTrackLine } from '../data-model/edit-track-line.model';
import { WayPoint } from '../data-model/way-point.model';
import { wpt_pin16_data } from '../service/wpt-pin16-data';
import { wpt_pin32_data } from '../service/wpt-pin32-data';
import { g } from '../service/global-data'


@Component({
    selector: 'app-user-data',
    imports: [TreeModule, ContextMenuModule, ToastModule, ConfirmDialogModule, DrawerModule, DialogModule, ButtonModule, ProgressBarModule,
        InputTextModule, InputNumberModule, FormsModule, ColorPickerModule, CheckboxModule],
    providers: [MessageService, ConfirmationService, TreeDragDropService, ElectronService, DataSaveService],
    templateUrl: './user-data.html',
    styleUrl: './user-data.css',
})
export class UserData implements OnInit {
    disable = () => g.editing ? 'disabled' : '';
    user_data_tree: TreeNode[] = g.user_data_tree;
    selected: any; 
    messageService = inject(MessageService);
    confirmationService = inject(ConfirmationService);
    electronService = inject(ElectronService);
    dataSaveService = inject(DataSaveService);
    kmlWriterService = inject(KmlWriterService);
    trackLineService = inject(TrackLineService);

    wpt_pins_16 = wpt_pin16_data;
    wpt_pins_32 = wpt_pin32_data.map((pin) => {
        return {idx: wpt_pin32_data.indexOf(pin), img: pin};
    });

    context_menu_items!: MenuItem[];
    track_line_menu_items: MenuItem[] = [
        {
            label: '复制到编辑区',
            command: (event) => this.copy_to_track_edit(),
        },
        {
            separator: true,
        },
        {
            label: '保存为kml文件',
            command: (event) => this.save_kml_file(),
        },
        {
            separator: true,
        },
        {
            label: '编辑轨迹参数',
            command: (event) => {
                this.track_line_color = '#' + this.selected.red.toString(16).padStart(2, '0')
                                            + this.selected.green.toString(16).padStart(2, '0')
                                            + this.selected.blue.toString(16).padStart(2, '0');
                this.show_track_line_edit = true;
            },
        },
        {
            separator: true,
        },
        {
            label: '显示/隐藏轨迹',
            command: (event) => this.toggle_track_line_display(),
        },
        {
            separator: true,
        },
        {
            label: '删除轨迹',
            command: (event) => this.delete_track_line(),
        },
    ];
    way_point_menu_items: MenuItem[] = [
        {
            label: '保存为kml文件',
            command: (event) => this.save_kml_file(),
        },
        {
            separator: true,
        },
        {
            label: '更改图标',
            command: (event) => {
                this.show_select_wpt_pin_dialog = true;
            },
        },
        {
            separator: true,
        },
        {
            label: '显示/隐藏路点',
            command: (event) => {
                this.toggle_way_point_display();
            },
        },
        {
            separator: true,
        },
        {
            label: '删除路点',
            command: (event) => {
                this.delete_way_point();
            },
        },
    ];
    folder_menu_items: MenuItem[] = [
        {
            label: '保存为kml文件',
            command: (event) => this.save_kml_file(),
        },
        {
            separator: true,
        },
        {
            label: '新建文件夹',
            command: (event) => {
                this.new_folder_name = '新文件夹';
                this.show_new_folder_dialog = true;
            },
        },
        {
            separator: true,
        },
        {
            label: '重命名文件夹',
            command: (event) => {
                this.rename_folder_name = this.selected.label;
                this.show_rename_folder_dialog = true;
            },
        },
        {
            separator: true,
        },
        {
            label: '导入轨迹至本文件夹',
            command: (event) => {
                this.open_track_file();
            },
        },
        {
            separator: true,
        },
        {
            label: '显示文件夹下所有轨迹',
            command: (event) => {
                this.show_folder(this.selected);
            },
        },
        {
            separator: true,
        },
        {
            label: '隐藏文件夹下所有轨迹',
            command: (event) => {
                this.hide_folder(this.selected);
            },
        },
        {
            separator: true,
        },
        {
            label: '设置文件夹下所有轨迹显示样式',
            command: (event) => {
                this.folder_track_line_width = 2;
                this.folder_track_line_color = '#ff0000';
                this.folder_track_line_draw_endpoints = false;
                this.show_folder_style_dialog = true;
            },
        },
        {
            separator: true,
        },
        {
            label: '删除文件夹',
            command: (event) => this.delete_folder(),
        },
    ];

    show_track_line_edit = false;
    track_line_color: string = '#ff0000';

    new_folder_name = '';
    show_new_folder_dialog = false;

    rename_folder_name = '';
    show_rename_folder_dialog = false;

    show_folder_style_dialog = false;
    folder_track_line_width = 2;
    folder_track_line_color = '#ff0000';
    folder_track_line_draw_endpoints = false;

    show_select_wpt_pin_dialog = false;

    show_data_loading_dialog = false;
    show_data_saving_dialog = false;


    ngOnInit(): void {
        g.user_data = this;

        // 初始化从备份文件加载数据
        this.load_user_data();

        // 定时每分钟备份一次用户数据目录
        setInterval(() => {
            this.dataSaveService.save_user_data();
        }, 1 * 60 * 1000);

    }

    async load_user_data() {
        const that = this;
        this.show_data_loading_dialog = true;

        async function set_visible(node: any) {
            if ((node.type === 'track_line' || node.type === 'way_point') && node.visible) {
                g.visible_tracks.set(node.uuid, node);

                // 因某些原因可能造成visible_tracks和user_data树中数据的不一致，在这里补充纠正过来
                if (node.type === 'track_line' && !g.track_line_points_cache.has(node.uuid)) {
                    const track_data = await that.electronService.invoke('load-track-data', node.uuid);
                    if (!!track_data) {
                        g.track_line_points_cache.set(node.uuid, track_data);
                    } else {
                        // 应做特殊处理，一般不可达
                    }
                }
            } else if (node.type === 'folder') {
                for (const child of node.children) {
                    await set_visible(child);
                }
            }
        }

        try {
            const user_data = await this.electronService.invoke('load-user-data');
            if (!!user_data) {
                g.user_data_tree.pop();
                g.user_data_tree.push(user_data);
                g.root_node_list = g.user_data_tree[0].children;
            }

            const visible_track_uuids = await this.electronService.invoke('load-visible-tracks');

            if (!!visible_track_uuids && visible_track_uuids.length > 0) {
                // 先使用加载的轨迹visible uuid在Map中按顺序赋空值占位，并加载轨迹点数据。目的：保持轨迹显示顺序
                for (const track_uuid of visible_track_uuids) {
                    // 在可视轨迹缓存中占位，等待遍历节点树添加节点链接
                    g.visible_tracks.set(track_uuid, null);

                    // 加载轨迹点数据（路点不加载）
                    const track_data = await this.electronService.invoke('load-track-data', track_uuid);
                    if (!!track_data) {
                        g.track_line_points_cache.set(track_uuid, track_data);
                    } else {
                        // 路点不加载数据；对于轨迹应做特殊处理，一般不可达
                    }
                }

                // 再遍历树，为Map中已占位的uuid赋值实际的轨迹对象
                for (const node of g.root_node_list) {
                    await set_visible(node);
                }

                // 最后再检查一遍是否所有的占位的uuid是否都填充节点对象，没有的话删除（可能因为各种原因误带来的多余uuid）
                for (const track_uuid of visible_track_uuids) {
                    if (!g.visible_tracks.get(track_uuid)) {
                        g.visible_tracks.delete(track_uuid);
                    }
                 }
            } else {
                // 因某些原因可能造成visible_tracks未存档，在这里补充纠正过来（不参考原来的顺序）
                for (const node of g.root_node_list) {
                    await set_visible(node);
                }
            }

            // 如果没有数据加载的话，打开对话框之后马上关闭会出现故障（应该是PrimeNG的小bug），因此需加一段延迟
            setTimeout(() => {
                this.show_data_loading_dialog = false;
            }, 10);
            
            // 加载数据完成后重绘地图
            g.map_canvas.repaint();
        } catch (error) {
            setTimeout(() => {
                this.show_data_loading_dialog = false;
            }, 10);
            this.messageService.add({ severity: 'error', summary: '初始化数据加载失败' });
        }
    }

    onNodeExpand(event: any) {
        // 用于调试
        // console.log(event);
    }

    onNodeDrop(event: any) {
        const dragNode = event.dragNode;
        const dropNode = event.dropNode;

        // 如果拖放的目标节点不是文件夹，则插入到该节点之前
        if (dropNode.type !== 'folder') {
            const indexDropNode = dropNode.parent.children.indexOf(dropNode);
            dropNode.parent.children.splice(indexDropNode, 0, dragNode);
            delete dropNode.children;
        }
    }

    onNodeSelect(event: any) {
        this.repaint_over_backup();
    }

    // 默认再点击已选择节点后取消选择，禁用此功能
    onNodeUnselect(event: any) {
        const that = this;
        function wait_unselect_complete() {
            setTimeout(() => {
                if (!!that.selected) {
                    wait_unselect_complete();
                } else {
                    that.selected = event.node;
                }
            }, 10);
        }

        // 取消选择后有延时，需等待完成
        wait_unselect_complete();
    }

    async onNodeDoubleClick(event: any) {
        this.selected = event.node;
        if (this.selected.type === 'track_line') {
            if (!this.selected.visible) {
                this.selected.visible = true; 
                g.visible_tracks.set(this.selected.uuid, this.selected);
                if (!g.track_line_points_cache.has(this.selected.uuid)) {
                    const track_data = await this.electronService.invoke('load-track-data', this.selected.uuid);
                    if (!!track_data) {
                        g.track_line_points_cache.set(this.selected.uuid, track_data);
                    } else {
                        // 应做特殊处理，一般不可达
                    }
                }
            }

            // 双击之前/同时也触发了两次单击，适当延迟一段时间来尽量保证双击任务在单击任务完成之后再执行（不是最优方案）
            setTimeout(() => {
                g.map_canvas.zoom_to_track(this.selected);
                g.track_chart.refresh();
                g.track_info.refresh();
            }, 100);
        } else if (this.selected.type === 'way_point') {
            if (!this.selected.visible) {
                this.selected.visible = true; 
                g.visible_tracks.set(this.selected.uuid, this.selected);
            }
            g.map_canvas.zoom_to_fpx_fpy(12, this.selected.fpx, this.selected.fpy);
            g.track_chart.refresh();
            g.track_info.refresh();
        } else {
            g.map_canvas.repaint();
            g.track_chart.refresh();
            g.track_info.refresh();
        }
    }

    select_track_line(track_line_uuid: string) {
        this.recursive_select_node(this.user_data_tree[0], track_line_uuid);
        this.repaint_over_backup();
    }

    recursive_select_node(node: any, node_uuid: string) {
        if ((node.type === 'track_line' || node.type === 'way_point') && node.uuid === node_uuid) {
            this.selected = node;
        } else if (node.type === 'folder') {
            for (const child of node.children) {
                this.recursive_select_node(child, node_uuid);
            }
        }
    }

    select_way_point(way_point: WayPoint) {
        this.selected = way_point;
        this.repaint_over_backup();
    }

    onNodeContextMenuSelect(event: any) {
        if (event.node.type === 'track_line') {
            if (event.node.visible) {
                this.track_line_menu_items[6].label = '隐藏轨迹';
            } else {
                this.track_line_menu_items[6].label = '显示轨迹';
            }
            this.context_menu_items = this.track_line_menu_items;
        } else if (event.node.type === 'way_point') {
            if (event.node.visible) {
                this.way_point_menu_items[4].label = '隐藏路点';
            } else {
                this.way_point_menu_items[4].label = '显示路点';
            }
            this.context_menu_items = this.way_point_menu_items;
        } else if (event.node.type === 'folder') {
            this.context_menu_items = this.folder_menu_items;
        } 

        this.selected = event.node;
        this.repaint_over_backup();
    }

    async save_kml_file() {
        this.show_data_saving_dialog = true;
        const kml_text = await this.kmlWriterService.write_kml(this.selected);
        setTimeout(() => {
            this.show_data_saving_dialog = false;
        }, 10);

        try {
            const result = await this.electronService.invoke('save-track-file', {
                filename: this.selected.label + '.kml',
                file_content: kml_text,
            });

            if (result.canceled) return;

            if (!!result.error) {
                this.messageService.add({ severity: 'error', summary: '轨迹文件保存失败！', detail: result.error });
            }

            if (!!result.path) {
                this.messageService.add({ severity: 'success', summary: '轨迹文件保存成功！', detail: result.path });
            }
        } catch (error) {
            this.messageService.add({ severity: 'error', summary: '轨迹文件保存失败！'});
        }
    }

    change_track_line_color() {
        this.selected.red = parseInt(this.track_line_color.substring(1,3), 16);
        this.selected.green = parseInt(this.track_line_color.substring(3,5), 16);
        this.selected.blue = parseInt(this.track_line_color.substring(5,7), 16);
        this.trackLineService.compute_track_line_thumbnail(this.selected);
        this.repaint_over_backup();
    }

    repaint() {
        g.map_canvas.repaint();
        g.track_chart.refresh();
        g.track_info.refresh();
    }

     repaint_over_backup() {
        // 只有在选择新的节点（轨迹、路点、文件夹）时才调用repaint_over_backup，需要做以下重置操作
        g.selected_photo = null;  // 清除照片选择
        g.track_chart.selected_point = -1;  // 清除track_chart中selected_point选择. 如果下面track_chart和track_info的refresh顺序搞错的话，这里需要先清除

        g.map_canvas.repaint_over_backup();
        // track_chart和track_info的refresh应保持先后顺序，因为track_info中要用到track_chart中设置的selected_point值
        g.track_chart.refresh();
        g.track_info.refresh();
    }

    async toggle_track_line_display() {
        this.selected.visible = !this.selected.visible;
        if (this.selected.visible) {
            g.visible_tracks.set(this.selected.uuid, this.selected);
            if (!g.track_line_points_cache.has(this.selected.uuid)) {
                const track_data = await this.electronService.invoke('load-track-data', this.selected.uuid);
                if (!!track_data) {
                    g.track_line_points_cache.set(this.selected.uuid, track_data);
                } else {
                    // 应做特殊处理，一般不可达
                }
            }
        } else {
            g.visible_tracks.delete(this.selected.uuid);
        }
        this.repaint();
    }

    toggle_way_point_display() {
        this.selected.visible = !this.selected.visible;
        if (this.selected.visible) {
            g.visible_tracks.set(this.selected.uuid, this.selected);
        } else {
            g.visible_tracks.delete(this.selected.uuid);
        }
        this.repaint();
    }

    delete_track_line() {
        this.confirmationService.confirm({
            header: '确定要删除该轨迹？注意：此操作不可逆转！！！',
            message: this.selected.label,
            icon: 'pi pi-exclamation-triangle',
            rejectButtonProps: {
                label: '否',
                severity: 'secondary',
                outlined: true,
            },
            acceptButtonProps: {
                label: '是',
                severity: 'danger',
            },
            accept: () => {
                if (g.visible_tracks.has(this.selected.uuid)) {
                    g.visible_tracks.delete(this.selected.uuid);
                }
                if (g.track_line_points_cache.has(this.selected.uuid)) {
                    g.track_line_points_cache.delete(this.selected.uuid);
                }
                this.electronService.send('delete-track-data', this.selected.uuid);

                this.selected.parent.children.splice(this.selected.parent.children.indexOf(this.selected), 1);
                this.selected = null;

                this.repaint();
            },
            reject: () => {},
        });
    }

    delete_way_point() {
        this.confirmationService.confirm({
            header: '确定要删除该路点？',
            message: this.selected.label,
            icon: 'pi pi-exclamation-triangle',
            rejectButtonProps: {
                label: '否',
                severity: 'secondary',
                outlined: true,
            },
            acceptButtonProps: {
                label: '是',
                severity: 'danger',
            },
            accept: () => {
                if (g.visible_tracks.has(this.selected.uuid)) {
                    g.visible_tracks.delete(this.selected.uuid);
                }

                this.selected.parent.children.splice(this.selected.parent.children.indexOf(this.selected), 1);
                this.selected = null;

                this.repaint();
            },
            reject: () => {},
        });
    }

    create_new_folder() {
        const folder = {
            type: 'folder',
            label: this.new_folder_name,
            children: [],
        };
        this.selected.children.push(folder);

        this.selected.expanded = true;
        this.selected = folder;
    }

    async show_folder(node: any) {
        await this.recursive_show_node(node);
        this.repaint();
    }

    async recursive_show_node(node: any) {
        if (node.type === 'folder') {
            for (const child of node.children) {
                await this.recursive_show_node(child);
            } 
        }
        else if (node.type === 'track_line') {
            if (!node.visible) {
                g.visible_tracks.set(node.uuid, node);
                if (!g.track_line_points_cache.has(node.uuid)) {
                    const track_data = await this.electronService.invoke('load-track-data', node.uuid);
                    if (!!track_data) {
                        g.track_line_points_cache.set(node.uuid, track_data);
                    } else {
                        // 应做特殊处理，一般不可达
                    }
                }
                node.visible = true;
            }
        }
        else if (node.type === 'way_point') {
            if (!node.visible) {
                g.visible_tracks.set(node.uuid, node);
                node.visible = true;
            }
        }
    }

    async hide_folder(node: any) {
        this.recursive_hide_node(node);
        this.repaint();
    }

    recursive_hide_node(node: any) {
        if (node.type === 'folder') {
            for (const child of node.children) {
                this.recursive_hide_node(child);
            } 
        }
        else if (node.type === 'track_line' || node.type === 'way_point') {
            if (node.visible) {
                g.visible_tracks.delete(node.uuid);
            }
            node.visible = false;
        }
    }

    recursive_set_node_style(node: any) {
        if (node.type === 'folder') {
            for (const child of node.children) {
                this.recursive_set_node_style(child);
            } 
        }
        else if (node.type === 'track_line') {
            node.red = parseInt(this.folder_track_line_color.substring(1,3), 16);
            node.green = parseInt(this.folder_track_line_color.substring(3,5), 16);
            node.blue = parseInt(this.folder_track_line_color.substring(5,7), 16);
            this.trackLineService.compute_track_line_thumbnail(node);
            node.width = this.folder_track_line_width;
            node.draw_endpoints = this.folder_track_line_draw_endpoints;
        }
    }

    delete_folder() {
        if (!this.selected.parent) return;

        this.confirmationService.confirm({
            header: '确定要删除该文件夹？注意：此操作不可逆转！！！',
            message: this.selected.label,
            icon: 'pi pi-exclamation-triangle',
            rejectButtonProps: {
                label: '否',
                severity: 'secondary',
                outlined: true,
            },
            acceptButtonProps: {
                label: '是',
                severity: 'danger',
            },
            accept: () => {
                this.recursive_delete_node(this.selected);
                this.selected.parent.children.splice(this.selected.parent.children.indexOf(this.selected), 1);
                this.selected = null;
                this.repaint();
            },
            reject: () => {},
        });
    }

    recursive_delete_node(node: any) {
        if (node.type === 'folder') {
            // 根节点
            if (!node.parent) {
                return;
            }

            for (const child of node.children) {
                this.recursive_delete_node(child);
            }
        } else if (node.type === 'track_line') {
            if (g.visible_tracks.has(node.uuid)) {
                g.visible_tracks.delete(node.uuid);
            }
            if (g.track_line_points_cache.has(node.uuid)) {
                g.track_line_points_cache.delete(node.uuid);
            }
            this.electronService.send('delete-track-data', node.uuid);
        } else if (node.type === 'way_point') {
            if (g.visible_tracks.has(node.uuid)) {
                g.visible_tracks.delete(node.uuid);
            }
        }
    }

    async copy_to_track_edit() {
        const edit_track_line: EditTrackLine = structuredClone(this.selected);
        delete edit_track_line.parent;

        edit_track_line.label = '副本_' + edit_track_line.label;
        edit_track_line.uuid = uuid().replace(/-/g, '').toLowerCase();

        // 编辑区轨迹样式统一设定为缺省值
        edit_track_line.width = 2;
        edit_track_line.red = 0;
        edit_track_line.green = 255;
        edit_track_line.blue = 0;
        edit_track_line.alpha = 255;
        edit_track_line.draw_endpoints = true;
        edit_track_line.visible = true;

        edit_track_line.selected = false;
        edit_track_line.checked = false;

        edit_track_line.points = structuredClone(g.track_line_points_cache.get(this.selected.uuid));
        if (!edit_track_line.points) {
            edit_track_line.points = await this.electronService.invoke('load-track-data', this.selected.uuid);
        }

        this.trackLineService.compute_track_line_thumbnail(edit_track_line);

        edit_track_line.selected_point = Math.floor(edit_track_line.points!.length! / 2);
        edit_track_line.sel_start_idx = 0;
        edit_track_line.sel_end_idx = edit_track_line.points!.length - 1;
        edit_track_line.sel_alt_min = edit_track_line.alt_min;
        edit_track_line.sel_alt_max = edit_track_line.alt_max;
        edit_track_line.sel_distance = edit_track_line.distance;
        edit_track_line.sel_distance_horizon = edit_track_line.distance_horizon;
        edit_track_line.sel_climb = edit_track_line.climb;
        edit_track_line.sel_descent = edit_track_line.descent;
        edit_track_line.sel_time_begin = edit_track_line.time_begin;
        edit_track_line.sel_time_end = edit_track_line.time_end;
        edit_track_line.sel_duration = edit_track_line.duration;
        edit_track_line.sel_point_num = edit_track_line.point_num;

        g.track_edit.track_line_list.push(edit_track_line);
    }

    open_track_file() {
        g.header.open_track_file(this.selected.children);
        this.selected.expanded = true;
    }

}

